package org.train;

import java.awt.EventQueue;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.UIManager;

import org.ActionConstants;
import org.ApplicationException;
import org.ConfigLoader;

public class TrainController {
	private Train trainPanel;
	private DatagramSocket[] dataSockets;
	private Integer numberOfProcesses;

	public static void main(String[] args) {
		// Define LookAndFeel
		try {
			UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
			JFrame.setDefaultLookAndFeelDecorated(true);
			JDialog.setDefaultLookAndFeelDecorated(true);
		} catch (Throwable e) {
		}
		
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					TrainPanel trainPanel = new TrainPanel();
					new TrainController(trainPanel);
					trainPanel.setVisible(true);
				} catch (Throwable e) {
				}
			}
		});
	}
	
	public TrainController(Train trainPanel) throws ApplicationException {
		this.setTrainPanel(trainPanel);
		try {
			createSockets();
		} catch (SocketException e) {
			throw new ApplicationException(e.getMessage());
		}
		listenActions();
	}
	
	private void createSockets() throws SocketException {
		setNumberOfProcesses(new Integer(ConfigLoader.configBundle.getString("number.of.processes"))); 
		dataSockets = new DatagramSocket[getNumberOfProcesses()];
		
		for(int i=0; i < getNumberOfProcesses(); i++) {
			int portNumber = i + 1;
			String strTrainPort = "train.p" + portNumber;
			Integer trainPort = new Integer(ConfigLoader.configBundle.getString(strTrainPort));
			dataSockets[i] = new DatagramSocket(trainPort);
		}
	}
	
	public void listenActions() {
		Runnable[] actionListeners = new Runnable[getNumberOfProcesses()];
		for (int i=0; i < getNumberOfProcesses(); i++) {
			actionListeners[i] = new Runnable() {
				public void run() {
					byte[] buffer = new byte[32];
					ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buffer);
					DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
					DatagramPacket dataPacket = new DatagramPacket(buffer, buffer.length);
					
					int i = Integer.parseInt(Thread.currentThread().getName());  
					while (true) {
						try {
							getTrainPanel().logMessage("Pronto para receber na Porta: " + dataSockets[i].getLocalPort(), false);
							dataSockets[i].receive(dataPacket);
							
							byteArrayInputStream.reset();
							int actionNumber = dataInputStream.readInt();
							doAction(actionNumber);
							
						} catch (IOException e) { }
					}
				}
			};
			new Thread(actionListeners[i], new Integer(i).toString()).start();
		}
	}
	
	synchronized public void doAction(Integer actionNumber) {
		switch (actionNumber) {
		case ActionConstants.INIT_MOVEMENT :
			getTrainPanel().logMessage("Iniciando Movimento...", true);
			getTrainPanel().moveString();
			break;
		case ActionConstants.PAUSE_MOVEMENT :
			getTrainPanel().logMessage("Pausando Movimento...", true);
			getTrainPanel().pauseString();
			break;
		}
	}
	
	/*
	 * GETTERS AND SETTERS
	 */

	private Train getTrainPanel() {
		return trainPanel;
	}

	private void setTrainPanel(Train trainPanel) {
		this.trainPanel = trainPanel;
	}

	private Integer getNumberOfProcesses() {
		return numberOfProcesses;
	}

	private void setNumberOfProcesses(Integer numberOfProcesses) {
		this.numberOfProcesses = numberOfProcesses;
	}
}